<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>webdriver_python</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
/* Author: Nicolas Hery - http://nicolashery.com */
/* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
/* Source: https://github.com/nicolahery/markdownpad-github */

/* RESET
=============================================================================*/

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
}

/* BODY
=============================================================================*/

body {
  font-family: Helvetica, arial, freesans, clean, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: #333;
  background-color: #fff;
  padding: 20px;
  max-width: 960px;
  margin: 0 auto;
}

body>*:first-child {
  margin-top: 0 !important;
}

body>*:last-child {
  margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
  margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
  margin: 20px 0 10px;
  padding: 0;
  font-weight: bold;
  -webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
  font-size: inherit;
}

h1 {
  font-size: 28px;
  color: #000;
}

h2 {
  font-size: 24px;
  border-bottom: 1px solid #ccc;
  color: #000;
}

h3 {
  font-size: 18px;
}

h4 {
  font-size: 16px;
}

h5 {
  font-size: 14px;
}

h6 {
  color: #777;
  font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
  margin-top: 0;
  padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
  margin-top: 0;
  padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
  margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
  color: #4183C4;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
  padding-left: 30px;
}

ul li > :first-child, 
ol li > :first-child, 
ul li ul:first-of-type, 
ol li ol:first-of-type, 
ul li ol:first-of-type, 
ol li ul:first-of-type {
  margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
  margin-bottom: 0;
}

dl {
  padding: 0;
}

dl dt {
  font-size: 14px;
  font-weight: bold;
  font-style: italic;
  padding: 0;
  margin: 15px 0 5px;
}

dl dt:first-child {
  padding: 0;
}

dl dt>:first-child {
  margin-top: 0px;
}

dl dt>:last-child {
  margin-bottom: 0px;
}

dl dd {
  margin: 0 0 15px;
  padding: 0 15px;
}

dl dd>:first-child {
  margin-top: 0px;
}

dl dd>:last-child {
  margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
  font-size: 12px;
  font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
  margin: 0 0px;
  padding: 0px 0px;
  white-space: nowrap;
  border: 1px solid #eaeaea;
  background-color: #f8f8f8;
  border-radius: 3px;
}

pre>code {
  margin: 0;
  padding: 0;
  white-space: pre;
  border: none;
  background: transparent;
}

pre {
  background-color: #f8f8f8;
  border: 1px solid #ccc;
  font-size: 13px;
  line-height: 19px;
  overflow: auto;
  padding: 6px 10px;
  border-radius: 3px;
}

pre code, pre tt {
  background-color: transparent;
  border: none;
}

kbd {
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    -moz-border-right-colors: none;
    -moz-border-top-colors: none;
    background-color: #DDDDDD;
    background-image: linear-gradient(#F1F1F1, #DDDDDD);
    background-repeat: repeat-x;
    border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
    border-image: none;
    border-radius: 2px 2px 2px 2px;
    border-style: solid;
    border-width: 1px;
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
    line-height: 10px;
    padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
  border-left: 4px solid #DDD;
  padding: 0 15px;
  color: #777;
}

blockquote>:first-child {
  margin-top: 0px;
}

blockquote>:last-child {
  margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
  clear: both;
  margin: 15px 0;
  height: 0px;
  overflow: hidden;
  border: none;
  background: transparent;
  border-bottom: 4px solid #ddd;
  padding: 0;
}

/* TABLES
=============================================================================*/

table th {
  font-weight: bold;
}

table th, table td {
  border: 1px solid #ccc;
  padding: 6px 13px;
}

table tr {
  border-top: 1px solid #ccc;
  background-color: #fff;
}

table tr:nth-child(2n) {
  background-color: #f8f8f8;
}

/* IMAGES
=============================================================================*/

img {
  max-width: 100%
}
</style>
<style type="text/css">
.highlight  { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
</style>
</head>
<body>
<h1>乙醇的webdriver实用指南Python版本</h1>

<h3>本书由乙醇所著，未经授权一律不得转载</h3>

<p>你可以通过如下方式与乙醇取得联系</p>

<h3>qq群</h3>

<ul>
<li>189116036</li>
<li>187032507</li>
<li>244735278</li>
</ul><h3>微博</h3>

<ul>
<li><a href="http://weibo.com/autootest">http://weibo.com/autootest</a></li>
</ul><h3>微信</h3>

<ul>
<li>在微信公众号中搜索<strong>乙醇</strong>或<strong>besttest</strong>
</li>
</ul><h3>besttest</h3>

<ul>
<li><a href="http://www.besttest.cn">www.besttest.cn</a></li>
</ul><hr><h1>启动浏览器</h1>

<h2>场景</h2>

<p>在使用webdriver进行测试时启动浏览器无疑是必须的前置工作。</p>

<h2>代码</h2>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>

</pre></div>

<h2>讨论</h2>

<p>自己试着弄清楚如何启动IE和Firefox</p>

<hr><h1>关闭浏览器</h1>

<h2>场景</h2>

<p>在脚本运行完毕或者测试代码结束的时候关闭浏览器是非常自然的事情，就像在吃完饭后就把餐桌收拾干净一样。</p>

<p>关闭浏览器有两种方式：</p>

<ul>
<li><p>close方法</p></li>
<li><p>quit方法</p></li>
</ul><p>close方法关闭当前的浏览器窗口，quit方法不仅关闭窗口，还会彻底的退出webdriver，释放与driver server之间的连接。所以简单来说quit是更加彻底的close，quit会更好的释放资源，适合强迫症和完美主义者。</p>

<h2>代码</h2>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">'browser will be closed'</span>
<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span> <span class="c"># or dr.close()</span>
<span class="k">print</span> <span class="s">'browser is closed'</span>
</pre></div>

<hr><h1>浏览器最大化</h1>

<h2>场景</h2>

<p>当我们在测试中使用一些基于图像和坐标的辅助测试工具时，我们就会需要使浏览器在每次测试时保存最大化，以便在同一分辨率下进行图像比对和坐标点选。</p>

<p>举例来说，如果在webdriver测试中使用了sikuli来对flash插件进行操作的话，把浏览器最大化无疑是一个比较简单的保证分辨率统一的解决方案。</p>

<h2>代码</h2>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">'maximize browser'</span>

<span class="n">dr</span><span class="o">.</span><span class="n">maximize_window</span><span class="p">()</span>

<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">'close browser'</span>

<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<hr><h1>设置浏览器大小</h1>

<h2>场景</h2>

<p>设置浏览器窗口的大小有下面两个比较常见的用途：</p>

<ul>
<li><p>在统一的浏览器大小下运行用例，可以比较容易的跟一些基于图像比对的工具进行结合，提升测试的灵活性及普遍适用性。比如可以跟sikuli结合，使用sikuli操作flash；</p></li>
<li><p>在不同的浏览器大小下访问测试站点，对测试页面截图并保存，然后观察或使用图像比对工具对被测页面的前端样式进行评测。比如可以将浏览器设置成移动端大小(320x480)，然后访问移动站点，对其样式进行评估；</p></li>
</ul><h2>代码</h2>

<p>将浏览器调整成移动端大小，然后访问移动站点，对移动站点的样式进行评估。</p>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>

<span class="n">dr</span><span class="o">.</span><span class="n">set_window_size</span><span class="p">(</span><span class="mi">240</span><span class="p">,</span> <span class="mi">320</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'http://www.3g.qq.com'</span><span class="p">)</span>

<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<h2>讨论</h2>

<p>webdriver提供了很多调整浏览器窗口的接口，比如set_window_position(设置或获取浏览器的位置)。在一般情况下这些功能并不常用。</p>

<hr><h1>访问链接</h1>

<h2>情景</h2>

<p>web UI测试里最简单也是最基本的事情就是访问1个链接了。</p>

<p>在python的webdrive中，访问url时应该使用get方法。</p>

<h2>代码</h2>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>

<span class="n">url</span> <span class="o">=</span> <span class="s">'http://www.baidu.com'</span>
<span class="k">print</span> <span class="s">"now access </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
</pre></div>

<hr><h1>打印当前页面的title及url</h1>

<h2>情景</h2>

<p>测试中，访问1个页面然后判断其title是否符合预期是很常见的1个用例，所谓用例不够，title来凑就是这个道理。更具体一点，假设1个页面的title应该是'hello world', 那么可以写这样的一个用例：访问该页面，获取该页面的title，判断获取的值是否等于'hello world'。</p>

<p>获取当前页面的url也是非常重要的一个操作。在某些情况下，你访问一个url，这时系统会自动对这个url进行跳转，这就是所谓的'重定向'。一般测试重定向的方法是访问这个url，然后等待页面重定向完毕之后，获取当前页面的url，判断该url是否符合预期。另外的一个常见的测试场景是提交了一个表单，如果表单内容通过了验证，那么则会跳转到一个新页面，如果未通过验证，则会停留在当前页面，此时获取当前页面的url则可以帮助我们判断表单提交的跳转是否符合预期。更具体一点，假如你在测试一个登陆页面，输入正确的登陆信息后，会跳转到系统首页。获取跳转后的url然后判断其是否与系统首页的url相符将是一个很不错的用例。</p>

<h2>代码</h2>

<div class="highlight highlight-python"><pre><span class="c"># -*- coding: utf-8 -*- </span>
<span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">sleep</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">if</span> <span class="s">'HTTP_PROXY'</span><span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span> <span class="k">del</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s">'HTTP_PROXY'</span><span class="p">]</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">url</span> <span class="o">=</span> <span class="s">'http://www.baidu.com'</span>
<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>

<span class="k">print</span> <span class="s">"title of current page is </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">dr</span><span class="o">.</span><span class="n">title</span><span class="p">)</span>
<span class="k">print</span> <span class="s">"url of current page is </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">dr</span><span class="o">.</span><span class="n">current_url</span><span class="p">)</span>

<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<hr><h1>前进和后退</h1>

<h2>场景</h2>

<p>说实话，这两个功能一般不太常用。所能想到的场景大概也就是在几个页面间来回跳转，省去每次都get url。</p>

<h2>代码</h2>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">sleep</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">if</span> <span class="s">'HTTP_PROXY'</span><span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span> <span class="k">del</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s">'HTTP_PROXY'</span><span class="p">]</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>

<span class="n">first_url</span> <span class="o">=</span> <span class="s">'http://www.baidu.com'</span>
<span class="k">print</span> <span class="s">"now access </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">first_url</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">first_url</span><span class="p">)</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">second_url</span> <span class="o">=</span> <span class="s">'http://www.news.baidu.com'</span>
<span class="k">print</span> <span class="s">"now access </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">second_url</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">second_url</span><span class="p">)</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="k">print</span> <span class="s">"back to </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">first_url</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">back</span><span class="p">()</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span> <span class="s">"forward to </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span><span class="p">(</span><span class="n">second_url</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">forward</span><span class="p">()</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
</pre></div>

<hr><h1>简单的对象定位</h1>

<h2>场景</h2>

<p>测试对象的定位和操作是webdriver的核心内容，其中操作又是建立在定位的基础之上,因此对象定位就越发显得重要了。</p>

<p>定位对象的目的一般有下面几种</p>

<ul>
<li>操作对象</li>
<li>获得对象的属性，如获得测试对象的class属性，name属性等等</li>
<li>获得对象的text</li>
<li>获得对象的数量</li>
</ul><p>webdriver提供了一系列的对象定位方法，常用的有以下几种</p>

<ul>
<li>id</li>
<li>name</li>
<li>class name</li>
<li>link text</li>
<li>partial link text</li>
<li>tag name</li>
<li>xpath</li>
<li>css selector</li>
</ul><h2>代码</h2>

<h3>html代码 form.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;Form&lt;/title&gt;
      &lt;script type="text/javascript" async="" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;
      &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;h3&gt;simple login form&lt;/h3&gt;
      &lt;form class="form-horizontal"&gt;
        &lt;div class="control-group"&gt;
          &lt;label class="control-label" for="inputEmail"&gt;Email&lt;/label&gt;
          &lt;div class="controls"&gt;
            &lt;input type="text" id="inputEmail" placeholder="Email" name="email"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="control-group"&gt;
          &lt;label class="control-label" for="inputPassword"&gt;Password&lt;/label&gt;
          &lt;div class="controls"&gt;
            &lt;input type="password" id="inputPassword" placeholder="Password" name="password"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="control-group"&gt;
          &lt;div class="controls"&gt;
            &lt;label class="checkbox"&gt;
              &lt;input type="checkbox"&gt; Remember me
            &lt;/label&gt;
            &lt;button type="submit" class="btn"&gt;Sign in&lt;/button&gt;
            &lt;a href="#"&gt;register&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/form&gt;
    &lt;/body&gt;
  &lt;/html&gt;
</code></pre>

<h3>python代码 simple_locate.rb</h3>

<div class="highlight highlight-python"><pre><span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">sleep</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">if</span> <span class="s">'HTTP_PROXY'</span><span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span> <span class="k">del</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s">'HTTP_PROXY'</span><span class="p">]</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="s">'file:///'</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="s">'form.html'</span><span class="p">)</span>
<span class="k">print</span> <span class="n">file_path</span>

<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>

<span class="c"># by id</span>
<span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_id</span><span class="p">(</span><span class="s">'inputEmail'</span><span class="p">)</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>

<span class="c"># by name</span>
<span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_name</span><span class="p">(</span><span class="s">'password'</span><span class="p">)</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>

<span class="c"># by tagname</span>
<span class="k">print</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_tag_name</span><span class="p">(</span><span class="s">'form'</span><span class="p">)</span><span class="o">.</span><span class="n">get_attribute</span><span class="p">(</span><span class="s">'class'</span><span class="p">)</span>

<span class="c"># by class_name</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_class_name</span><span class="p">(</span><span class="s">'controls'</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">execute_script</span><span class="p">(</span><span class="s">'$(arguments[0]).fadeOut().fadeIn()'</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="c"># by link text</span>
<span class="n">link</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_link_text</span><span class="p">(</span><span class="s">'register'</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">execute_script</span><span class="p">(</span><span class="s">'$(arguments[0]).fadeOut().fadeIn()'</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="c"># by partial link text</span>
<span class="n">link</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_partial_link_text</span><span class="p">(</span><span class="s">'reg'</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">execute_script</span><span class="p">(</span><span class="s">'$(arguments[0]).fadeOut().fadeIn()'</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="c"># by css selector</span>
<span class="n">div</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_css_selector</span><span class="p">(</span><span class="s">'.controls'</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">execute_script</span><span class="p">(</span><span class="s">'$(arguments[0]).fadeOut().fadeIn()'</span><span class="p">,</span> <span class="n">div</span><span class="p">)</span>
<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="c"># by xpath</span>
<span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_xpath</span><span class="p">(</span><span class="s">'/html/body/form/div[3]/div/label/input'</span><span class="p">)</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>

<span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<h2>讨论</h2>

<p>上面例子里由于html文件中引用了jquery，所以在执行js时可以使用jquery的$()及fadeIn()等方法。如果你测试的页面没用包含jquery的话，这些方法是无效的。</p>

<hr><h1>定位一组对象</h1>

<h2>场景</h2>

<p>从上一节的例子中可以看出，webdriver可以很方便的使用find_element方法来定位某个特定的对象，不过有时候我们却需要定位一组对象，这时候就需要使用find_elements方法。</p>

<p>定位一组对象一般用于以下场景：</p>

<ul>
<li>批量操作对象，比如将页面上所有的checkbox都勾上</li>
<li>先获取一组对象，再在这组对象中过滤出需要具体定位的一些对象。比如定位出页面上所有的checkbox，然后选择最后一个</li>
</ul><h2>代码</h2>

<h3>checkbox.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;Checkbox&lt;/title&gt;
            &lt;script type="text/javascript" async="" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;
            &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;checkbox&lt;/h3&gt;
            &lt;div class="well"&gt;
                &lt;form class="form-horizontal"&gt;
                    &lt;div class="control-group"&gt;
                        &lt;label class="control-label" for="c1"&gt;checkbox1&lt;/label&gt;
                        &lt;div class="controls"&gt;
                            &lt;input type="checkbox" id="c1" /&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class="control-group"&gt;
                        &lt;label class="control-label" for="c2"&gt;checkbox2&lt;/label&gt;
                        &lt;div class="controls"&gt;
                            &lt;input type="checkbox" id="c2" /&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class="control-group"&gt;
                        &lt;label class="control-label" for="c3"&gt;checkbox3&lt;/label&gt;
                        &lt;div class="controls"&gt;
                            &lt;input type="checkbox" id="c3" /&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;                      
                    &lt;div class="control-group"&gt;
                        &lt;label class="control-label" for="r"&gt;radio&lt;/label&gt;
                        &lt;div class="controls"&gt;
                            &lt;input type="radio" id="r" /&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;                      
                &lt;/form&gt;
            &lt;/div&gt;
        &lt;/body&gt;
    &lt;/html&gt;
</code></pre>

<h3>find_element.rb</h3>

<pre><code>    #encoding: utf-8
    require 'selenium-webdriver'

    dr = Selenium::WebDriver.for :chrome
    file_path = 'file:///' + File.expand_path(File.join('.', 'checkbox.html'))

    dr.get file_path

    # 选择所有的checkbox并全部勾上
    dr.find_elements(:css, 'input[type=checkbox]').each {|c| c.click}
    dr.navigate.refresh()
    sleep 1

    # 打印当前页面上有多少个checkbox
    puts dr.find_elements(:css, 'input[type=checkbox]').size

    # 选择页面上所有的input，然后从中过滤出所有的checkbox并勾选之
    dr.find_elements(:tag_name, 'input').each do |input|
        input.click if input.attribute(:type) == 'checkbox'
    end 
    sleep 1

    # 把页面上最后1个checkbox的勾给去掉
    dr.find_elements(:css, 'input[type=checkbox]').last.click

    sleep 2
    dr.quit
</code></pre>

<h2>讨论</h2>

<p>checkbox.html必须与find_elments.rb在同一级目录下</p>

<hr><h1>层级定位</h1>

<h2>场景</h2>

<p>在实际的项目测试中，经常会有这样的需求：页面上有很多个属性基本相同的元素，现在需要具体定位到其中的一个。由于属性基本相当，所以在定位的时候会有些麻烦，这时候就需要用到层级定位。先定位父元素，然后再通过父元素定位子孙元素。</p>

<h2>代码</h2>

<p>下面的代码演示了如何通过层级定位来定位下拉菜单中的某一项。由于两个下拉菜单中每个选项的link text都相同，href也一样，所以在这里就需要使用层级定位了。</p>

<p>具体思路是：先点击显示出1个下拉菜单，然后再定位到该下拉菜单所在的ul，再定位这个ul下的某个具体的link。在这里，我们定位第1个下拉菜单中的Another action这个选项。</p>

<h3>level_locate.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;Level Locate&lt;/title&gt;     
            &lt;script type="text/javascript" async="" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;Level locate&lt;/h3&gt;
            &lt;div class="span3"&gt;     
                &lt;div class="well"&gt;
                    &lt;div class="dropdown"&gt;
                        &lt;a class="dropdown-toggle" data-toggle="dropdown" href="#"&gt;Link1&lt;/a&gt;
                        &lt;ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" id="dropdown1" &gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Another action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Something else here&lt;/a&gt;&lt;/li&gt;
                            &lt;li class="divider"&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Separated link&lt;/a&gt;&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/div&gt;              
                &lt;/div&gt;          
            &lt;/div&gt;
            &lt;div class="span3"&gt;     
                &lt;div class="well"&gt;
                    &lt;div class="dropdown"&gt;
                        &lt;a class="dropdown-toggle" data-toggle="dropdown" href="#"&gt;Link2&lt;/a&gt;
                        &lt;ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" &gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Another action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Something else here&lt;/a&gt;&lt;/li&gt;
                            &lt;li class="divider"&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Separated link&lt;/a&gt;&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/div&gt;              
                &lt;/div&gt;          
            &lt;/div&gt;
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;

</code></pre>

<h3>level_locate.py</h3>

<div class="highlight highlight-python"><pre><span class="c"># -*- coding: utf-8 -*-</span>
<span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">selenium.webdriver.support.ui</span> <span class="kn">import</span> <span class="n">WebDriverWait</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">os</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">file_path</span> <span class="o">=</span>  <span class="s">'file:///'</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="s">'level_locate.html'</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_link_text</span><span class="p">(</span><span class="s">'Link1'</span><span class="p">)</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>

<span class="n">WebDriverWait</span><span class="p">(</span><span class="n">dr</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span><span class="o">.</span><span class="n">until</span><span class="p">(</span><span class="k">lambda</span> <span class="n">the_driver</span><span class="p">:</span> <span class="n">the_driver</span><span class="o">.</span><span class="n">find_element_by_id</span><span class="p">(</span><span class="s">'dropdown1'</span><span class="p">)</span><span class="o">.</span><span class="n">is_displayed</span><span class="p">())</span>
<span class="n">menu</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_id</span><span class="p">(</span><span class="s">'dropdown1'</span><span class="p">)</span><span class="o">.</span><span class="n">find_element_by_link_text</span><span class="p">(</span><span class="s">'Another action'</span><span class="p">)</span>

<span class="n">webdriver</span><span class="o">.</span><span class="n">ActionChains</span><span class="p">(</span><span class="n">dr</span><span class="p">)</span><span class="o">.</span><span class="n">move_to_element</span><span class="p">(</span><span class="n">menu</span><span class="p">)</span><span class="o">.</span><span class="n">perform</span><span class="p">()</span>

<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<h2>讨论</h2>

<p>move_to方法实际上是模拟把鼠标移动到某个具体的测试对象上。</p>

<hr><h1>操作测试对象</h1>

<h2>场景</h2>

<p>定位到具体的对象后，我们就可以对这个对象进行具体的操作，比如先前已经看到过的点击操作(click)。一般来说，webdriver中比较常用的操作对象的方法有下面几个</p>

<ul>
<li>click 点击对象</li>
<li>send_keys 在对象上模拟按键输入</li>
<li>clear 清除对象的内容，如果可以的话</li>
</ul><h2>代码</h2>

<p>下面的代码演示了如何点击元素，如何往文本框中输入文字以及如何清空文字。</p>

<h3>operate_element.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;Level Locate&lt;/title&gt;     
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;Level locate&lt;/h3&gt;
            &lt;div class="span3"&gt;     
                &lt;div class="well"&gt;
                    &lt;div class="dropdown"&gt;
                        &lt;a class="dropdown-toggle" data-toggle="dropdown" href="#"&gt;Link1&lt;/a&gt;
                        &lt;ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" id="dropdown1" &gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Another action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Something else here&lt;/a&gt;&lt;/li&gt;
                            &lt;li class="divider"&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Separated link&lt;/a&gt;&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/div&gt;              
                &lt;/div&gt;          
            &lt;/div&gt;
            &lt;div class="span3"&gt;     
                &lt;div class="well"&gt;
                    &lt;div class="dropdown"&gt;
                        &lt;a class="dropdown-toggle" data-toggle="dropdown" href="#"&gt;Link2&lt;/a&gt;
                        &lt;ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" &gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Another action&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Something else here&lt;/a&gt;&lt;/li&gt;
                            &lt;li class="divider"&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Separated link&lt;/a&gt;&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/div&gt;              
                &lt;/div&gt;          
            &lt;/div&gt;
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>operate_element.py</h3>

<div class="highlight highlight-python"><pre><span class="c"># -*- coding: utf-8 -*-</span>
<span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">os</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">file_path</span> <span class="o">=</span>  <span class="s">'file:///'</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="s">'operate_element.html'</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>

<span class="c"># click</span>
<span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_link_text</span><span class="p">(</span><span class="s">'Link1'</span><span class="p">)</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_link_text</span><span class="p">(</span><span class="s">'Link1'</span><span class="p">)</span><span class="o">.</span><span class="n">click</span><span class="p">()</span>

<span class="c"># send_keys</span>
<span class="n">element</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_name</span><span class="p">(</span><span class="s">'q'</span><span class="p">)</span>
<span class="n">element</span><span class="o">.</span><span class="n">send_keys</span><span class="p">(</span><span class="s">'something'</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="c"># clear</span>
<span class="n">element</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<hr><h1>send keys模拟按键输入</h1>

<h2>场景</h2>

<p>send_keys方法可以模拟一些组合键操作，比如ctrl+a等。另外有时候我们需要在测试时使用tab键将焦点转移到下一个元素，这时候也需要send_keys。在某些更复杂的情况下，还会出现使用send_keys来模拟上下键来操作下拉列表的情况。</p>

<h2>代码</h2>

<p>下面的代码演示了如何将A多行文本框中的内容清空并复制到B文本框中。</p>

<h3>send_keys.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;send keys&lt;/title&gt;        
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;send keys&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
            &lt;div class="span3"&gt;     
                &lt;div class="well"&gt;
                    &lt;label&gt;A&lt;/label&gt;
                    &lt;textarea rows="10", cols="10" id="A"&gt;I think watir-webdriver is better than selenium-webdriver&lt;/textarea&gt;
                &lt;/div&gt;          
            &lt;/div&gt;
            &lt;div class="span3"&gt;     
                &lt;div class="well"&gt;
                    &lt;label&gt;B&lt;/label&gt;
                    &lt;textarea rows="10", cols="10" id="B"&gt;&lt;/textarea&gt;
                &lt;/div&gt;          
            &lt;/div&gt;
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>send_keys.py</h3>

<pre><code>from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('send_keys.html')

dr.get(file_path)

# copy content of A
dr.find_element_by_id('A').send_keys((Keys.CONTROL, 'a'))
dr.find_element_by_id('A').send_keys((Keys.CONTROL, 'x'))
sleep(1)

# paste to B
dr.find_element_by_id('B').send_keys((Keys.CONTROL, 'v'))
sleep(1)

# # send keys to A
dr.find_element_by_id('A').send_keys('watir', '-', 'webdriver', Keys.SPACE, 'is', Keys.SPACE, 'better')
sleep(2)

dr.quit()

</code></pre>

<hr><h1>处理button group</h1>

<h2>场景</h2>

<p>button group就是按钮组，将一组按钮排列在一起。处理这种对象的思路一般是先找到button group的包裹(wrapper)div，然后通过层级定位，用index或属性去定位更具体的按钮。</p>

<h2>代码</h2>

<p>下面的代码演示了如何找到second这个按钮。其处理方法是先找到button group的父div，class为btn-group的div，然后再找到下面所有的div(也就是button)，返回text是second的div。</p>

<h3>button_group.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;button group&lt;/title&gt;     
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('.btn').click(function(){
                        alert($(this).text());
                    });
                });         
            &lt;/script&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;button group&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span3"&gt;     
                    &lt;div class="well"&gt;
                        &lt;div class="btn-toolbar"&gt;
                            &lt;div class="btn-group"&gt;
                                &lt;div class="btn"&gt;first&lt;/div&gt;
                                &lt;div class="btn"&gt;second&lt;/div&gt;
                                &lt;div class="btn"&gt;third&lt;/div&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;          
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>button_group.py</h3>

<div class="highlight highlight-python"><pre><span class="c"># -*- coding: utf-8 -*- </span>
<span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">selenium.webdriver.common.keys</span> <span class="kn">import</span> <span class="n">Keys</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">sleep</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">if</span> <span class="s">'HTTP_PROXY'</span><span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span> <span class="k">del</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s">'HTTP_PROXY'</span><span class="p">]</span>

<span class="n">dr</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Chrome</span><span class="p">()</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="s">'file:///'</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="s">'button_group.html'</span><span class="p">)</span>

<span class="n">dr</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>

<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="c"># 定位text是second的按钮</span>
<span class="n">buttons</span> <span class="o">=</span> <span class="n">dr</span><span class="o">.</span><span class="n">find_element_by_class_name</span><span class="p">(</span><span class="s">'btn-group'</span><span class="p">)</span><span class="o">.</span><span class="n">find_elements_by_class_name</span><span class="p">(</span><span class="s">'btn'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">btn</span> <span class="ow">in</span> <span class="n">buttons</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">btn</span><span class="o">.</span><span class="n">text</span> <span class="o">==</span> <span class="s">'second'</span><span class="p">:</span> <span class="k">print</span> <span class="s">'find second button'</span>

<span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">dr</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

</pre></div>

<h2>讨论</h2>

<p>自己查资料搞清楚detect方法的作用。</p>

<hr><h1>处理button dropdown</h1>

<h2>场景</h2>

<p>button dropdown就是把按钮和下拉菜单弄到了一起。处理这种对象的思路一般是先点击这个按钮，等待下拉菜单显示出来，然后使用层级定位方法来获取下拉菜单中的具体项。</p>

<h2>代码</h2>

<p>下面的代码演示了如何找到watir-webdriver这个菜单项。其处理方法是先点击info按钮，然后等到下拉菜单出现后定位下拉菜单的ul元素，再定位ul元素中link text为watir-webdriver的link，并点击之。</p>

<h3>button_dropdown.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;button group&lt;/title&gt;     
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('.btn').click(function(){
                        alert($(this).text());
                    });
                });         
            &lt;/script&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;button group&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span3"&gt;     
                    &lt;div class="well"&gt;
                        &lt;div class="btn-toolbar"&gt;
                            &lt;div class="btn-group"&gt;
                                &lt;div class="btn"&gt;first&lt;/div&gt;
                                &lt;div class="btn"&gt;second&lt;/div&gt;
                                &lt;div class="btn"&gt;third&lt;/div&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;          
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>button_dropdown.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('button_group.html')

dr.get(file_path)

sleep(1)

# 定位text是second的按钮
buttons = dr.find_element_by_class_name('btn-group').find_elements_by_class_name('btn')
for btn in buttons:
    if btn.text == 'second': print 'find second button'

sleep(1)
dr.quit()

</code></pre>

<hr><h1>处理navs</h1>

<h2>场景</h2>

<p>navs可以看作是简单的类似于tab的导航栏。一般来说导航栏都是ul+li。先定位ul再去层级定位li中的link基本就能解决问题。</p>

<h2>代码</h2>

<h3>navs.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;Navs&lt;/title&gt;     
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(
                    function(){
                        $('.nav').find('li').click(function() {
                            $(this).parent().find('li').removeClass('active');
                            $(this).addClass('active');
                        });
                    }
                );
            &lt;/script&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;Navs&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span3"&gt;     
                    &lt;ul class="nav nav-pills"&gt;
                        &lt;li class="active"&gt;
                            &lt;a href="#"&gt;Home&lt;/a&gt;
                        &lt;/li&gt;
                        &lt;li&gt;&lt;a href="#"&gt;Content&lt;/a&gt;&lt;/li&gt;
                        &lt;li&gt;&lt;a href="#"&gt;About&lt;/a&gt;&lt;/li&gt;
                    &lt;/ul&gt;
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>navs.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('navs.html')

dr.get(file_path)

sleep(1)

# 方法1：层级定位，先定位ul再定位li
dr.find_element_by_class_name('nav').find_element_by_link_text('About').click()
sleep(1)

# 方法2: 直接定位link
dr.find_element_by_link_text('Home').click()
sleep(1)

dr.quit()

</code></pre>

<hr><h1>处理面包屑</h1>

<h2>场景</h2>

<p>在实际的测试脚本中，有可能需要处理面包屑。处理面包屑主要是获取其层级关系，以及获得当前的层级。一般来说当前层级都不会是链接，而父层级则基本是以链接，所以处理面包屑的思路就很明显了。找到面包屑所在的div或ul，然后再通过该div或ul找到下面的所有链接，这些链接就是父层级。最后不是链接的部分就应该是当前层级了。</p>

<h2>代码</h2>

<h3>breadcrumb.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;breadcrumb&lt;/title&gt;       
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(
                    function(){

                    }
                );
            &lt;/script&gt;
        &lt;/head&gt;
        &lt;body&gt;
            &lt;h3&gt;breadcrumb&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span3"&gt;     
                    &lt;ul class="breadcrumb"&gt;
                        &lt;li&gt;&lt;a href="#"&gt;Home&lt;/a&gt; &lt;span class="divider"&gt;/&lt;/span&gt;&lt;/li&gt;
                        &lt;li&gt;&lt;a href="#"&gt;Library&lt;/a&gt; &lt;span class="divider"&gt;/&lt;/span&gt;&lt;/li&gt;
                        &lt;li class="active"&gt;Data&lt;/li&gt;
                    &lt;/ul&gt;
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;

</code></pre>

<h3>breadcrumb.rb</h3>

<pre><code>    #encoding: utf-8
    require 'selenium-webdriver'

    dr = Selenium::WebDriver.for :chrome
    file_path = 'file:///' + File.expand_path(File.join('.', 'breadcrumb.html'))
    dr.get file_path

    # 获得其父层级
    anstors = dr.find_element(:class, 'breadcrumb').find_elements(:tag_name, 'a').map { |link| link.text }
    p anstors
    sleep(1)

    # 获取当前层级
    # 由于页面上可能有很多class为active的元素
    # 所以使用层级定位最为保险
    puts dr.find_element(:class, 'breadcrumb').find_element(:class, 'active').text

    dr.quit()

</code></pre>

<hr><h1>处理分页</h1>

<h2>场景</h2>

<p>对分页来说，我们最感兴趣的是下面几个信息</p>

<ul>
<li>总共有多少页</li>
<li>当前是第几页</li>
<li>是否可以上一页和下一页</li>
</ul><h2>代码</h2>

<p>下面的代码演示了如何获取分页的总数以及当前是第几页</p>

<h3>pagination.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;Pagination&lt;/title&gt;       
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('.pagination').find('li').click(function(){
                        $(this).parent().find('li').removeClass('active');
                        $(this).addClass('active');
                    });
                });
            &lt;/script&gt;
        &lt;/head&gt;

        &lt;body&gt;
            &lt;h3&gt;Pagination&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span6"&gt;     
                    &lt;div class="pagination pagination-large"&gt;
                        &lt;ul&gt;
                            &lt;li&gt;&lt;a href="#"&gt;Prev&lt;/a&gt;&lt;/li&gt;
                            &lt;li class="active"&gt;&lt;a href="#"&gt;1&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a href="#"&gt;2&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a href="#"&gt;3&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a href="#"&gt;4&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a href="#"&gt;5&lt;/a&gt;&lt;/li&gt;
                            &lt;li&gt;&lt;a href="#"&gt;Next&lt;/a&gt;&lt;/li&gt;
                        &lt;/ul&gt;
                    &lt;/div&gt;
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;

</code></pre>

<h3>pagination.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('pagination.html')

dr.get(file_path)

# 获得所有分页的数量
# -2是因为要去掉上一个和下一个
total_pages = len(dr.find_element_by_class_name('pagination').find_elements_by_tag_name('li')) - 2
print "total page is %s" %(total_pages)

# 获取当前页面的url以及当前页面是第几页
current_page = dr.find_element_by_class_name('pagination').find_element_by_class_name('active')
print "current page is %s" %(current_page.text)

dr.quit()

</code></pre>

<hr><h1>处理对话框</h1>

<h2>场景</h2>

<p>页面上弹出的对话框是自动化测试经常会遇到的一个问题。很多情况下这个弹出的对话框是一个iframe，处理起来有点麻烦，需要进行switch_to操作。但现在很多前端框架的对话框都是div形式的，这就让我们的处理变得十分简单了。</p>

<p>处理对话框一般会做下面的一些事情</p>

<ul>
<li>打开对话框</li>
<li>关闭对话框</li>
<li>操作对话框中的元素</li>
</ul><h2>代码</h2>

<p>下面的代码演示了如何打开、关闭以及点击对话框中的链接</p>

<h3>modal.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;modal&lt;/title&gt;        
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('#click').click(function(){
                        $(this).parent().find('p').text('try watir-webdriver right now!');
                    });
                });
            &lt;/script&gt;
        &lt;/head&gt;

        &lt;body&gt;
            &lt;h3&gt;modal&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span6"&gt;     
                    &lt;!-- Button to trigger modal --&gt;
                    &lt;a href="#myModal" role="button" class="btn btn-primary" data-toggle="modal" id="show_modal"&gt;Click&lt;/a&gt;

                    &lt;!-- Modal --&gt;
                    &lt;div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"&gt;
                      &lt;div class="modal-header"&gt;
                        &lt;button type="button" class="close" data-dismiss="modal" aria-hidden="true"&gt;×&lt;/button&gt;
                        &lt;h3 id="myModalLabel"&gt;Modal header&lt;/h3&gt;
                      &lt;/div&gt;
                      &lt;div class="modal-body"&gt;
                        &lt;p&gt;watir-webdriver is better than slenium-webdriver&lt;/p&gt;
                        &lt;a href="#" id="click"&gt;click me&lt;/a&gt;
                      &lt;/div&gt;
                      &lt;div class="modal-footer"&gt;
                        &lt;button class="btn" data-dismiss="modal" aria-hidden="true"&gt;Close&lt;/button&gt;
                        &lt;button class="btn btn-primary"&gt;Save changes&lt;/button&gt;
                      &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;

</code></pre>

<h3>modal.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
import selenium.webdriver.support.ui as ui
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('modal.html')

dr.get(file_path)

# 打开对话框
dr.find_element_by_id('show_modal').click()

wait = ui.WebDriverWait(dr, 10)
wait.until(lambda dr: dr.find_element_by_id('myModal').is_displayed())

# 点击对话框中的链接
# 由于对话框中的元素被蒙板所遮挡，直接点击会报 Element is not clickable的错误
# 所以使用js来模拟click
# 在watir-webdriver中只需要fire_event(:click)就可以了
link = dr.find_element_by_id('myModal').find_element_by_id('click')
dr.execute_script('$(arguments[0]).click()', link)
sleep(2)

# 关闭对话框
buttons = dr.find_element_by_class_name('modal-footer').find_elements_by_tag_name('button')
buttons[0].click()

dr.quit()

</code></pre>

<hr><h1>获取测试对象的属性及内容</h1>

<h2>场景</h2>

<p>获取测试对象的内容是前端自动化测试里一定会使用到的技术。比如我们要判断页面上是否显示了一个提示，那么我们就需要找到这个提示对象，然后获取其中的文字，再跟我们的预期进行比较。在webdriver中使用element.attribute()方法可以获取dom元素(测试对象)的属性。</p>

<p>获取测试对象的属性能够帮我们更好的进行对象的定位。比如页面上有很多class都是'btn'的div，而我们需要定位其中1个有具有title属性的div。由于selenium-webdriver是不支持直接使用title来定位对象的，所以我们只能先把所有class是btn的div都找到，然后遍历这些div，获取这些div的title属性，一旦发现具体title属性的div，那么返回这个div既可。在webdriver中，使用element.text()方法可以返回dom节点的内容(text)。</p>

<h2>代码</h2>

<p>下面的代码演示了如何获取测试对象的title属性和该对象的文字内容</p>

<h3>attribute.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;attribute&lt;/title&gt;        
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('#tooltip').tooltip({"placement": "right"});
                });
            &lt;/script&gt;
        &lt;/head&gt;

        &lt;body&gt;
            &lt;h3&gt;attribute&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span6"&gt;     
                    &lt;a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver"&gt;hover to see tooltip&lt;/a&gt;
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>attribute.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('attribute.html')

dr.get(file_path)

link = dr.find_element_by_id('tooltip')

sleep(1)
# 获得tooltip的内容
print link.get_attribute('data-original-title')

# 获取该链接的text
print link.text

dr.quit()

</code></pre>

<hr><h1>获取测试对象的css属性</h1>

<h2>场景</h2>

<p>当你的测试用例纠结细枝末节的时候，你就需要通过判断元素的css属性来验证你的操作是否达到了预期的效果。比如你可以通过判断页面上的标题字号以字体来验证页面的显示是否符合预期。当然，这个是强烈不推荐的。因为页面上最不稳定的就是css了，css变动频繁，而且通过属性也不能直观的判断页面的显示效果，还不如让人为的去看一眼，大问题一望即知。</p>

<h2>代码</h2>

<p>下面的代码演示了如何获取测试对象的css属性。</p>

<h3>css.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;attribute&lt;/title&gt;        
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('#tooltip').tooltip({"placement": "right"});
                });
            &lt;/script&gt;
        &lt;/head&gt;

        &lt;body&gt;
            &lt;h3&gt;attribute&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span6"&gt;     
                    &lt;a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver"&gt;hover to see tooltip&lt;/a&gt;
                &lt;/div&gt;      
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>css.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('css.html')

dr.get(file_path)

link = dr.find_element_by_id('tooltip')
print link.value_of_css_property('color')

print dr.find_element_by_tag_name('h3').value_of_css_property('font')

dr.quit()

</code></pre>

<hr><h1>获取测试对象的状态</h1>

<h2>场景</h2>

<p>在web自动化测试中，我们需要获取测试对象的四种状态</p>

<ul>
<li>是否显示。使用element.is_displayed()方法；</li>
<li>是否存在。使用find_element_by_xxx方法，捕获其抛出的异常, 如果存在异常的话则可以确定该元素不存在；</li>
<li>是否被选中。一般是判断表单元素，比如radio或checkbox是否被选中。使用element.is_selected()方法；</li>
<li>是否enable，也就是是否是灰化状态。使用element.is_enabled()方法；</li>
</ul><h2>代码</h2>

<h3>status.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;status&lt;/title&gt;       
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                    $('#tooltip').tooltip({"placement": "right"});
                });
            &lt;/script&gt;
        &lt;/head&gt;

        &lt;body&gt;
            &lt;h3&gt;status&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span3"&gt;     
                    &lt;input name="user" placeholder="Disabled TextField" disabled  /&gt;                
                &lt;/div&gt;      
                &lt;div class="span3"&gt;
                    &lt;a class="btn disabled"&gt;Disabled Button&lt;/a&gt;
                &lt;/div&gt;
                &lt;div class="span3"&gt;
                    &lt;input name="radio" type="radio" /&gt;
                &lt;/div&gt;
            &lt;/div&gt;      
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>status.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('status.html')
dr.get(file_path)

text_field = dr.find_element_by_name('user')
print text_field.is_enabled()

# 直接用enabled?方法去判断该button的话返回的会是true
# 这是因为button是使用css方法去disabled的，并不是真正的disable
# 这时候需要判断其class里是否有disabled这值来判断其是否处于disable状态
print dr.find_element_by_class_name('btn').is_enabled()

# 隐藏掉text_field
# 判断其是否显示
dr.execute_script('$(arguments[0]).hide()', text_field)
print text_field.is_displayed()

# 使用click方法选择raido
radio = dr.find_element_by_name('radio')
radio.click()
print radio.is_selected()

# 判断元素是否存在
try:
    dr.find_element_by_id('none')
except: 
    print 'element does not exist'

dr.quit()

</code></pre>

<h2>讨论</h2>

<p>在这里我们遇到了一种情况，那就是测试对象看上去是disabled，但是使用enabled方法却返回true。这时候一般思路是判断该对象的css属性或class，通过这些值去进一步判断对象是否disable。</p>

<hr><h1>form的操作</h1>

<h2>场景</h2>

<p>表单对象的操作比较简单，只需要记住下面几点</p>

<ul>
<li>使用send_keys方法往多行文本框和单行文本框赋值；</li>
<li>使用click方法选择checkbox</li>
<li>使用click方法选择radio</li>
<li>使用click方法点击button</li>
<li>使用click方法选择option，从而达到选中select下拉框中某个具体菜单项的效果</li>
</ul><h2>代码</h2>

<h3>form.html</h3>

<pre><code>    &lt;html&gt;
        &lt;head&gt;
            &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
            &lt;title&gt;form&lt;/title&gt;     
            &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
            &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;      
            &lt;script type="text/javascript"&gt;
                $(document).ready(function(){
                        $('input[type=submit]').click(function(){
                            alert('watir-webdriver is better than selenium webdriver');
                        });
                });
            &lt;/script&gt;
        &lt;/head&gt;

        &lt;body&gt;
            &lt;h3&gt;form&lt;/h3&gt;
            &lt;div class="row-fluid"&gt;
                &lt;div class="span6 well"&gt;        
                    &lt;form&gt;
                        &lt;fieldset&gt;
                            &lt;legend&gt;Legend&lt;/legend&gt;                     
                            &lt;label class="checkbox"&gt;
                                &lt;input type="checkbox"&gt; Check me out
                            &lt;/label&gt;

                            &lt;label class="radio"&gt;
                                &lt;input type="radio"&gt; select me 
                            &lt;/label&gt;

                            &lt;label class="select"&gt;
                                &lt;select&gt;
                                    &lt;option&gt;0&lt;/option&gt;
                                    &lt;option&gt;1&lt;/option&gt;
                                    &lt;option&gt;2&lt;/option&gt;
                                &lt;/select&gt; select one item
                            &lt;/label&gt;

                            &lt;input type="submit" class="btn" value="submit" /&gt;
                        &lt;/fieldset&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/body&gt;
        &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
    &lt;/html&gt;
</code></pre>

<h3>form.rb</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('form.html')
dr.get(file_path)

# 选中checkbox
dr.find_element_by_css_selector('input[type=checkbox]').click()
sleep(1)

# 选中radio
dr.find_element_by_css_selector('input[type=radio]').click()
sleep(1)

# 选择下拉菜单中的最后一项
dr.find_element_by_tag_name('select').find_elements_by_tag_name('option')[-1].click()
sleep(1)

# 点击提交按钮
dr.find_element_by_css_selector('input[type=submit]').click()
sleep(10)

alert = dr.switch_to_alert()
print alert.text
alert.accept()

dr.quit()

</code></pre>

<hr><h1>执行js</h1>

<h2>场景</h2>

<p>如果你熟悉js的话，那么使用webdriver执行js就是一件很高效的事情了。在webdriver脚本中直接执行js的好处很多，这里就不一一枚举了。</p>

<p>webdriver提供了execute_script()接口来帮助我们完成这一工作。在实际的测试脚本中，以下两种场景是经常遇到的</p>

<ul>
<li>在页面直接执行一段js</li>
<li>在某个已经定位的元素的上执行js</li>
</ul><h2>代码</h2>

<p>下面的代码演示了如何在页面以及在已经定位的元素上执行js</p>

<h3>js.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;js&lt;/title&gt;     
      &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;        
      &lt;script type="text/javascript"&gt;
        $(document).ready(function(){
          $('#tooltip').tooltip({"placement": "right"});
        });
      &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
      &lt;h3&gt;js&lt;/h3&gt;
      &lt;div class="row-fluid"&gt;
        &lt;div class="span6 well"&gt;        
          &lt;a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver"&gt;hover to see tooltip&lt;/a&gt;
          &lt;a class="btn"&gt;Button&lt;/a&gt;
        &lt;/div&gt;      
      &lt;/div&gt;        
    &lt;/body&gt;
    &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;/html&gt;

</code></pre>

<h3>js.python</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('js.html')
dr.get(file_path)

# 在页面上直接执行js
dr.execute_script('$("#tooltip").fadeOut();')
sleep(1)

# 在已经定位的元素上执行js
button = dr.find_element_by_class_name('btn')
dr.execute_script('$(arguments[0]).fadeOut()', button)
sleep(1)

dr.quit()

</code></pre>

<hr><h1>处理alert/confirm/prompt</h1>

<h2>场景</h2>

<p>webdriver中处理原生的js alert confirm 以及prompt是很简单的。具体思路是使用switch_to.alert()方法定位到alert/confirm/prompt。然后使用text/accept/dismiss/send_keys按需进行操做</p>

<ul>
<li>text。返回alert/confirm/prompt中的文字信息</li>
<li>accept。点击确认按钮</li>
<li>dismiss。点击取消按钮，如果有的话</li>
<li>send_keys。向prompt中输入文字</li>
</ul><h2>代码</h2>

<p>下面代码简单的演示了如何去处理原生的alert</p>

<h3>alert.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;alert&lt;/title&gt;      
      &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;        
      &lt;script type="text/javascript"&gt;
        $(document).ready(function(){
          $('#tooltip').tooltip({"placement": "right"});
          $('#tooltip').click(function(){
              alert('watir-webdriver better than selenium-webdriver')
          });
        });
      &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
      &lt;div class="row-fluid"&gt;
        &lt;div class="span6 well"&gt;        
          &lt;h3&gt;alert&lt;/h3&gt;
          &lt;a id="tooltip" href="#" data-toggle="tooltip" title="watir-webdriver better than selenium-webdriver"&gt;hover to see tooltip&lt;/a&gt;
        &lt;/div&gt;      
      &lt;/div&gt;        
    &lt;/body&gt;
    &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;/html&gt;
</code></pre>

<h3>alert.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('alert.html')
dr.get(file_path)

# 点击链接弹出alert
dr.find_element_by_id('tooltip').click()

try:
    alert = dr.switch_to_alert()
    alert.accept()
except:
    print 'no alerts display'

sleep(1)
dr.quit()

</code></pre>

<hr><h1>wait</h1>

<h2>场景</h2>

<p>Wait类的使用场景是在页面上进行某些操作，然后页面上就会出现或隐藏一些元素，此时使用Wait类的until方法来等待这些效果完成以便进行后续的操作。另外页面加载时有可能会执行一些ajax，这时候也需要去WebDriverWait的until的等待ajax的请求执行完毕。</p>

<p>具体一点的例子前面也曾出现过，点击一个链接然后会出现一个下拉菜单，此时需要先等待下拉菜单出现方可进行点击菜单项的操作。</p>

<p>这时候就需要用到selenium.webdriver.support.ui.WebDriverWait类，实例化该类时可以传入timeout的时间，单位是s。</p>

<p>until方法会一直等下去，直到</p>

<ul>
<li>代码块中的内容为true(不为false或没有抛出异常)</li>
<li>超时,也就是超过了timeout设置的时间</li>
</ul><h2>代码</h2>

<p>下面代码演示了点击按钮后如何等待label出现。这个例子其实没有前面的下拉菜单例子实用。</p>

<h3>wait.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;wait&lt;/title&gt;       
      &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;        
      &lt;script type="text/javascript"&gt;
        $(document).ready(function(){
            $('#btn').click(function(){
              $('&lt;p&gt;&lt;span class="label label-info"&gt;waitr-webdriver&lt;/span&gt;&lt;/p&gt;').css('margin-top', '1em').insertAfter($(this));
              $(this).addClass('disabled').unbind('click');
            });
        });
      &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
      &lt;div class="row-fluid"&gt;
        &lt;div class="span6 well"&gt;        
          &lt;h3&gt;wait&lt;/h3&gt;
          &lt;button class="btn btn-primary" id="btn" &gt;Click&lt;/button&gt;
        &lt;/div&gt;      
      &lt;/div&gt;        
    &lt;/body&gt;
    &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;/html&gt;
</code></pre>

<h3>wait.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
import selenium.webdriver.support.ui as ui
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('wait.html')

dr.get(file_path)

# 点击按钮
dr.find_element_by_id('btn').click()

wait = ui.WebDriverWait(dr, 10)
wait.until(lambda dr: dr.find_element_by_class_name('label').is_displayed())

sleep(2)
dr.quit()

</code></pre>

<hr><h1>定位frame中的元素</h1>

<h2>场景</h2>

<p>处理frame需要用到2个方法，分别是switch_to_frame(name_or_id_or_frame_element)和switch_to_default_content()</p>

<p>如何理解这个switch_to_frame(name_or_id_or_frame_element)方法呢？可以简单记忆一下，如果这个frame有name和id属性那么就用这两个属性就好，如果没有的话可以先用find_element_by_xxx方法找到这个frame元素，然后把这个元素传进去，这也是可行的。</p>

<p>switch_to_frame方法把当前定位的主体切换了frame里。怎么理解这句话呢？我们可以从frame的实质去理解。frame中实际上是嵌入了另一个页面，而webdriver每次只能在一个页面识别，因此才需要用switch_to_frame方法去获取frame中嵌入的页面，对那个页面里的元素进行定位。</p>

<p>switch_to_default_content方法的话则是从frame中嵌入的页面里跳出，跳回到最外面的原始页面中。</p>

<p>如果页面上只有1个frame的话那么这一切都是很好理解的，但如果页面上有多个frame，情况有稍微有点复杂了。</p>

<h2>代码</h2>

<p>下面的代码中frame.html里有个id为f1的frame，而f1中又嵌入了id为f2的frame，该frame加载了百度的首页。</p>

<h3>frame.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;frame&lt;/title&gt;      
      &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;        
      &lt;script type="text/javascript"&gt;
        $(document).ready(function(){
        });
      &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
      &lt;div class="row-fluid"&gt;
        &lt;div class="span10 well"&gt;       
          &lt;h3&gt;frame&lt;/h3&gt;
          &lt;iframe id="f1" src="inner.html" width="800", height="600"&gt;&lt;/iframe&gt;
        &lt;/div&gt;      
      &lt;/div&gt;        
    &lt;/body&gt;
    &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;/html&gt;
</code></pre>

<h3>inner.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;inner&lt;/title&gt;      
    &lt;/head&gt;

    &lt;body&gt;
      &lt;div class="row-fluid"&gt;
        &lt;div class="span6 well"&gt;        
          &lt;h3&gt;inner&lt;/h3&gt;
          &lt;iframe id="f2" src="http://www.baidu.com" width="700" height="500"&gt;&lt;/iframe&gt;
          &lt;a href="javascript:alert('watir-webdriver better than selenium webdriver;')"&gt;click&lt;/a&gt;
        &lt;/div&gt;      
      &lt;/div&gt;        
    &lt;/body&gt;
  &lt;/html&gt;
</code></pre>

<h3>frame.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
import selenium.webdriver.support.ui as ui
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('frame.html')

dr.get(file_path)

# 先到f1再到f2
dr.switch_to_frame('f1')
dr.switch_to_frame('f2')

# 往f2中的百度关键字文本框中输入内容
dr.find_element_by_id('kw').send_keys('watir-webdriver')

# 直接跳出所有frame
dr.switch_to_default_content()

# 再到f1
dr.switch_to_frame('f1')
dr.find_element_by_link_text('click').click()

sleep(2)
dr.quit()

</code></pre>

<h2>讨论</h2>

<p>假设页面上有A、B两个frame，其中B在A内，那么定位B中的内容则需要先到A，然后再到B。如果是定位A中的内容，那么直接switch_to_frame('A')就可以了;</p>

<p>switch_to.frame的参数问题。官方说name是可以的，但是经过实验发现id也可以。所以只要frame中id和name，那么处理起来是比较容易的。如果frame没有这两个属性的话，你可以直接加上，这对整个页面影响不大;</p>

<p>页面中使用frame会影响页面渲染速度，如果你遇到页面中有多个frame的情况，你完全可以提出1个页面前端性能的缺陷;</p>

<p>如果实在搞不定页面上的frame，送你一句歌词：也许放弃才能靠近你。那么及时放弃跟此frame相关的用例才是明智之举;</p>

<hr><h1>action</h1>

<h2>场景</h2>

<p>由于webdriver是要模拟真实的用户操作，因此webdriver的Action类中提供了很多与操作有关的方法。</p>

<p>下面列举一下Action类的一些主要方法</p>

<ul>
<li>key_down。模拟按键按下</li>
<li>key_up。模拟按键弹起</li>
<li>click</li>
<li>send_keys</li>
<li>double_click。鼠标左键双击</li>
<li>click_and_hold。鼠标左键点击住不放</li>
<li>release。鼠标左键弹起，可以与click_and_hold配合使用</li>
<li>move_to_element。把鼠标移动到元素的中心点</li>
<li>content_click。鼠标右键点击</li>
<li>drag_and_drop。拖拽</li>
</ul><h2>代码</h2>

<pre><code>from selenium.webdriver.common.action_chains import ActionChains

element = wd.find_element_by_link_text('xxxxx')
hov = ActionChains(wd).move_to_element(element)
hov.perform()
</code></pre>

<h2>讨论</h2>

<p>具体的api文档参考<a href="http://selenium-python.readthedocs.org/en/latest/api.html#module-selenium.webdriver.common.action_chains">这里</a></p>

<hr><h1>上传文件</h1>

<h2>场景</h2>

<p>上传文件的方法是找到上传文件的对象，通常是的对象。然后直接往这个对象send_keys，传入需要上传文件的正确路径。绝对路径和相对路径都可以，但是上传的文件必须存在，否则会报错。</p>

<h2>代码</h2>

<h3>upload_file.html</h3>

<pre><code>  &lt;html&gt;
    &lt;head&gt;
      &lt;meta http-equiv="content-type" content="text/html;charset=utf-8" /&gt;
      &lt;title&gt;upload_file&lt;/title&gt;        
      &lt;script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
      &lt;link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" /&gt;        
      &lt;script type="text/javascript"&gt;
      &lt;/script&gt;
    &lt;/head&gt;

    &lt;body&gt;
      &lt;div class="row-fluid"&gt;
        &lt;div class="span6 well"&gt;        
          &lt;h3&gt;upload_file&lt;/h3&gt;
          &lt;input type="file" name="file" /&gt;
        &lt;/div&gt;      
      &lt;/div&gt;        
    &lt;/body&gt;
    &lt;script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;/html&gt;
</code></pre>

<h3>upload_file.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()
file_path = 'file:///' + os.path.abspath('upload_file.html')

dr.get(file_path)

dr.find_element_by_name('file').send_keys('./upload_file.md')

sleep(2)
dr.quit()
</code></pre>

<hr><h1>下载</h1>

<h2>场景</h2>

<p>webdriver允许我们设置默认的文件下载路径。也就是说文件会自动下载并且存在设置的那个目录中。</p>

<p>下面会给出chrome和firefox浏览器的具体设置方法。</p>

<h2>代码</h2>

<pre><code>import os

from selenium import webdriver

fp = webdriver.FirefoxProfile()

fp.set_preference("browser.download.folderList",2)
fp.set_preference("browser.download.manager.showWhenStarting",False)
fp.set_preference("browser.download.dir", os.getcwd())
fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream")

browser = webdriver.Firefox(firefox_profile=fp)
browser.get("http://pypi.python.org/pypi/selenium")
browser.find_element_by_partial_link_text("selenium-2").click()

</code></pre>

<hr><h1>超时设置</h1>

<h2>场景</h2>

<p>webdriver中可以设置很多的超时时间</p>

<ul>
<li>implicit_wait。识别对象时的超时时间。过了这个时间如果对象还没找到的话就会抛出异常</li>
</ul><h2>代码</h2>

<pre><code>ff = webdriver.Firefox()
ff.implicitly_wait(10) # seconds
ff.get("http://somedomain/url_that_delays_loading")
myDynamicElement = ff.find_element_by_id("myDynamicElement")

</code></pre>

<hr><h1>cookie</h1>

<h2>场景</h2>

<p>webdriver可以读取并添加cookie。有时候我们需要验证浏览器中是否存在某个cookie，因为基于真实的cookie的测试是无法通过白盒和集成测试完成的。</p>

<p>另外更加常见的一个场景是自动登陆。有很多系统的登陆信息都是保存在cookie里的，因此只要往cookie中添加正确的值就可以实现自动登陆了。什么图片验证码、登陆的用例就都是浮云了。</p>

<h2>代码</h2>

<p>下面的代码演示了如何自动登陆百度。其中敏感信息我使用了xxxx来代替。</p>

<h3>cookie.py</h3>

<pre><code># -*- coding: utf-8 -*- 
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep
import os
if 'HTTP_PROXY'in os.environ: del os.environ['HTTP_PROXY']

dr = webdriver.Chrome()

url = 'http://www.baidu.com'
dr.get(url)

print dr.get_cookies()
dr.delete_all_cookies()
dr.add_cookie({'name': 'BAIDUID', 'value': 'xxxxxx'})
dr.add_cookie({'name': 'BDUSS', 'value': 'xxxxxx'})

dr.get(url)

sleep(3)
dr.quit()

</code></pre>
</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->
